home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Media 22
/
PC MEDIA CD22.iso
/
share
/
prog
/
datalib2
/
dataexe2.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-14
|
14KB
|
409 lines
/*
This is part 2 of the expression evaluator
*/
#include "datapriv.hpp"
/************************************************************************
This is the actual expression evaluator, it takes a pointer to a pointer
to a string, and returns an integer representing the value of the string.
It also updates the string pointer to point to the first character after
the expression.
************************************************************************/
op *expval::exeval(char **s,record *recp)
{
char ws[255],*wsp,*wsp1;
struct op *rv;
exworkp=exwork;
if (**s==EXSTART) rv=evalstr(s,0,recp); /* Already tokenised */
else
{
wsp1=ws;
wsp=exetoken(*s,&wsp1); /* Tokenise the string */
wsp1=ws;
rv=evalstr(&wsp1,0,recp);
*s=wsp;
}
memcpy(&retop,rv,sizeof(struct op));
return(&retop);
}
/*
This routine evaluates a tokenised string, returning an integer which
is the value of the string.
It takes a pointer to a pointer to a string, and updates it to point to
the first character after the expression, it is recursive, lop should
point be the priority of a previous operator, and initially should be set
to 0.
*/
op *expval::evalstr(char **s,int ilop,record *recp)
{
int end=0; // flag end of expression
int thisst=0; // Shows this started with EXSTART
struct op funcpar[16]; // function parameters
struct op *fo,*so; /* First and second operands */
char c; /* Temporary char */
time_t tclock; /* Current time */
struct tm *tms;
char *wsp; /* Local work space */
int lop=ilop;
int x,y,z; // useful ints
field *f; // field
double rnum,fnum,snum; // Floats used in evaluation
int rint,fint,sint; // Integers used in evaluation
int rlen,flen; // Length of result,1st op
char *rstr,*fstr; // First string, Result string
int copflag;
if (**s==EXSTART) {(*s)++; lop=0; thisst=1;} /* Skip expression marker */
c=**s; (*s)++;
fo=(struct op *)exealloc(sizeof(struct op));
fo->optype=OPINT;
fo->num=0;
if (c<0) /* Must be a number or string of some sort */
switch(c)
{
case EXINT : fo->num=**(double **)s; *s+=sizeof(double);
break;
case EXVAR : x=**(int **)s; *s+=sizeof(int);
f=db->getfield(x);
switch(f->type)
{
case 'C' : fo->optype=OPSTR;
fo->str=exealloc(f->getlen()+1);
strcpy(fo->str,recp->getfield(x,0));
fo->oplen=f->getlen();
break;
case 'N' : fo->num=atof(recp->getfield(x)); break;
case 'L' : fo->optype=OPLOG;
x=*(char *)(recp->getfield(x)) & 0xdf;
fo->num=(x=='Y' || x=='T') ? 1 : 0; break;
case 'D' : fo->optype=OPDATE;
strncpy(fo->date,recp->getfield(x),8);
fo->date[8]=0;
break;
case 'M' : fo->optype=OPSTR; fo->str=recp->getfield(x,0);
if (recp->indflg) err("No Memo in index");
break;
}
break;
case EXSTR : fo->optype=OPSTR; fo->str=strcpy(exealloc(strlen(*s)+1),*s);
fo->oplen=strlen(fo->str);
while(**s) (*s)++; (*s)++;
break;
case EXSTART : (*s)--; fo=evalstr(s,0,recp); break;
default : err("Error in expression - a"); goto errend;
}
else /* Must be an operator, or a function */
if (oppt[c].type==BINARY)
{err("Error in expression - b"); goto errend;}
else
{
so=funcpar+1;
if ((oppt[c].type!=FUNCTION) || ((oppt[c].type==FUNCTION) && oppt[c].pri))
{
// Now for a function collect the correct number of parameters, however
// to speed the program type checking is performed on the first 2
// parameters, and fo copies the 1st par. and so points to the 2nd
// The only parameter retained is fo.
if (oppt[c].type>=FUNCTION)
{
for(int i=0; i<oppt[c].pri+oppt[c].type-4; funcpar[i++]=*evalstr(s,99,recp));
*fo=funcpar[0];
if (!(fo->optype & oppt[c].type1) ||
(oppt[c].pri>1 && !(so->optype & oppt[c].type2)))
{err("Wrong operand type F"); goto errend;}
}
else // Unary operator, pick up the operand
{
fo=evalstr(s,oppt[c].num==NOT ? oppt[c].pri : 99,recp);
if (!(fo->optype & oppt[c].type1))
{err("Wrong operand type 1"); goto errend;}
}
}
if (fo->optype==OPINT || fo->optype==OPLOG) {fint=fnum=fo->num;}
if (fo->optype==OPSTR) {fstr=fo->str; flen=strlen(fstr)+1;}
if (so->optype==OPINT) {sint=snum=so->num;}
if (oppt[c].optype) fo->optype=oppt[c].optype;
rlen=fo->oplen;
rint=-1000;
copflag=1; // Show if result needs copying after evaluation
switch(oppt[c].num) // Unary operations
{
case PLUS : copflag=0; break;
case MINUS : rnum=-fnum; break;
case NOT : rint=(!fint) ? -1 : 0; break;
case ABS : rnum=fabs(fnum); break;
case ASC : rint=*fstr; break;
case AT : wsp=strstr(so->str,fstr);
rint=(wsp) ? wsp-so->str+1 : 0; break;
case CDOW : rstr=strcpy(exealloc(9),cdow(fo->date)); rlen=9; break;
case CHR : rstr=exealloc(2); *rstr=fint; rstr[1]=0; rlen=1; break;
case CMONTH : rstr=strcpy(exealloc(10),cmonth(fo->date)); rlen=9; break;
case CTOD : rstr=fstr; ctod(fo->date,rstr); break;
case DATE : time(&tclock); strcpy(fo->date,getdate(tclock)); break;
case DAY : gnums(fo->date,rint,y,z); break;
case DOW : rint=dow(fo->date); break;
case DTOC : rstr=exealloc(11); gnums(fo->date,x,y,z);
sprintf(rstr,"%02d/%02d/%02d",x,y,z%100); rlen=8;
break;
case DTOS : rstr=strcpy(exealloc(9),fo->date); rlen=8; break;
case IIF : if (recp->indflg)
{
if (so->optype!=funcpar[2].optype) err("Inv Ind");
rlen=(so->oplen>funcpar[2].oplen) ?
so->oplen : funcpar[2].oplen;
}
if (fint) *fo=*so; else *fo=funcpar[2]; copflag=0;
break;
case INT : rnum=(fnum>=0) ? floor(fnum) : ceil(fnum); break;
case ISALPHA: rint=isalpha(*(fstr)); break;
case ISDIGIT: rint=isdigit(*(fstr)); break;
case ISLOWER: rint=islower(*(fstr)); break;
case ISUPPER: rint=isupper(*(fstr)); break;
case LEFT : if (sint<1) {*fstr=0; rlen=0;}
else {if (flen-1>sint) fstr[sint]=0; rlen=sint;}
copflag=0; break;
case LOWER : rstr=strlwr(fstr); break;
case UPPER : rstr=strupr(fstr); break;
case LTRIM : rstr=fstr; while(*rstr==' ') rstr++; break;
case LEN : rint=flen-1; break;
case MAX : if (fo->optype==OPDATE)
{if (strcmp(fo->date,so->date)<0) *fo=*so;}
else if (fnum<snum) *fo=*so;
copflag=0;
break;
case MIN : if (fo->optype==OPDATE)
{if (strcmp(fo->date,so->date)>0) *fo=*so;}
else if (fnum>snum) *fo=*so;
copflag=0;
break;
case MOD : rnum=fmod(fnum,snum); break;
case MONTH : gnums(fo->date,x,rint,z); break;
case RECCOUNT : rnum=db->getnrec(); break;
case RECNO : rnum=recp->getrecnum(); break;
case RECSIZE : rint=db->getreclen(); break;
case REPLICATE :
rstr=exealloc(flen*sint); *rstr=0; rlen=sint*(flen-1);
for(x=0; x<sint; x++) strcat(rstr,fstr);
break;
case RIGHT : if (sint<1) {*fstr=0; rlen=0;}
else {if (sint<flen-1) fstr+=flen-1-sint; rlen=sint;}
rstr=fstr; break;
case ROUND : if (snum>=0)
{
wsp=exealloc(32); sprintf(wsp,"%%.%df",sint);
sprintf(exworkp,wsp,fnum); rnum=atof(exworkp);
exworkp=wsp;
}
else // Negative rounding
{
rnum=floor(fnum/pow(10,-sint)+0.5)*pow(10,-sint);
}
break;
case TRIM :
case RTRIM : rstr=rtrim(fstr); break;
case SOUNDEX: rstr=soundex(exealloc(5),fstr); rlen=4; break;
case SPACE : if (fint<0) fint=0;
rstr=wsp=exealloc(1+fint); rlen=fint;
while(wsp<exworkp-1) *wsp++=' '; *wsp=0;
break;
case STR : wsp=exealloc(32);
if (funcpar[2].optype!=1) {err("No. expected"); goto errend;}
x=(sint==-1) ? 10 : sint;
y=(funcpar[2].num==-1) ? 0 : funcpar[2].num;
sprintf(wsp,"%%%d.%df",x,y);
sprintf(exworkp,wsp,fnum); exworkp[x]=0;
rstr=exealloc(strlen(exworkp)+1);
rlen=x;
break;
case STUFF : if (funcpar[2].optype!=OPINT || funcpar[3].optype!=OPSTR)
{err("Wrong par. type"); goto errend;}
x=sint; if (!x) x=1;
rstr=exealloc(strlen(funcpar[3].str)+flen);
strcpy(rstr,fstr);
if (x>strlen(rstr))
{fo->str=strcat(rstr,funcpar[3].str); break;}
rstr[x-1]=0; strcat(rstr,funcpar[3].str);
if(x+funcpar[2].num<flen)
strcat(rstr,fstr+(int)(x+(int)(funcpar[2].num)-1));
rlen=fo->oplen-funcpar[2].num;
if (rlen<0) rlen=0;
rlen+=sint-1+funcpar[3].oplen;
break;
case SUBSTR : if (sint<1) {*fstr=0; rlen=0;}
else if (sint<flen-1)
{
fstr+=sint-1;
x=funcpar[2].num;
if (x>0 && x<strlen(fstr)) *(fstr+x)=0;
rlen=(x>0) ? x : fo->oplen-sint+1;
}
rstr=fstr; break;
case SWAPDATA: rstr=swapdata(fstr); break;
case TIME : time(&tclock); rstr=exealloc(30);
strcpy(rstr,asctime(localtime(&tclock))+11); rlen=8;
rstr[8]=0;
break;
case TYPE : rstr=exealloc(2); rstr[1]=0;
switch(fo->optype)
{
case OPINT : *rstr='N'; break;
case OPSTR : *rstr='C'; break;
case OPDATE : *rstr='D'; break;
case OPLOG : *rstr='L'; break;
}
fo->optype=OPSTR; rlen=1; break;
case VAL : rnum=atof(fstr); break;
case YEAR : gnums(fo->date,x,y,rint); break;
}
fo->oplen=rlen; // Copy in results
if (copflag)
{
if (fo->optype==OPINT || fo->optype==OPLOG)
fo->num=(rint!=-1000) ? rint : rnum;
if (fo->optype==OPSTR) fo->str=rstr;
}
}
while(!end)
{
// We should now be pointing at the end of expression or a binary operator
// fo has been set to the value of the first operand
c=**s; (*s)++;
if (c==EXEND) {end=1; if (!thisst) (*s)--; return(fo);} // ret - end expr.
if (c<=OBRAC) {err("Error in expression - c"); goto errend;}
if (oppt[c].pri<=lop) {(*s)--; return(fo);} /* return if priority lower */
so=evalstr(s,oppt[c].pri,recp);
if (!((fo->optype & oppt[c].type1) && (so->optype & oppt[c].type2)))
{err("Wrong operand type 2"); goto errend;}
switch(oppt[c].num) /* Binary Operators */
{
case PLUS :
case MINUS : plumin(fo,so,oppt[c].num); break;
case DOLLAR : fo->num=(strstr(so->str,fo->str)!=0); fo->optype=OPLOG; break;
case POW2 :
case POW : fo->num=pow(fo->num,so->num); break;
case TIMES : fo->num*=so->num; break;
case DIVIDE : if (!so->num) {err("Divide by 0"); goto errend;}
fo->num/=so->num; break;
case AND : fo->num=(fo->num && so->num) ? -1 : 0; break;
case OR : fo->num=(fo->num || so->num) ? -1 : 0; break;
case GT :
case LT :
case GTE :
case LTE :
case NE :
case NE2 :
case EQUAL : execomp(fo,so,oppt[c].num); break;
}
}
return(fo);
errend: /* Find the end of the equation in case of error */
while(!end)
{
c=(**s); (*s)++;
switch(c)
{
case EXSTART : end++; break;
case EXINT : (*s)+=sizeof(float); break;
case EXSTR :
case EXVAR : while(**s) (*s)++; (*s)++; break;
case EXEND : end=1; if (!thisst) (*s)--; break;
}
}
return(fo);
}
/***************************************************************************/
// Handle plus and minus
void expval::plumin(struct op *fo, struct op *so,int in)
{
int n=(in==PLUS);
char *wsp;
if (fo->optype==OPINT && so->optype==OPINT) // number & number
{
fo->num-=so->num-2*n*so->num; return;
}
if (fo->optype==OPSTR && so->optype==OPSTR) // string & string
{
strcpy(exworkp,fo->str);
if (n) strcat(exworkp,so->str);
else
{
int x;
wsp=exworkp; while(*wsp++);
wsp--; wsp--; x=0; while(*wsp==' ') {wsp--; x++;}
wsp++; *wsp=0;
strcat(exworkp,so->str);
wsp=exworkp; while(*wsp++); wsp--; while(x--) *wsp++=' ';
*wsp=0;
}
fo->str=exealloc(strlen(exworkp)+1);
fo->oplen+=so->oplen;
return;
}
if (n && fo->optype==OPINT && so->optype==OPDATE)
{
op temp=*so; *so=*fo; *fo=temp;
}
if (fo->optype==OPDATE && so->optype==OPINT)
{
daystodate(fo->date,days(fo->date)-so->num+2*n*so->num); return;
}
if (!n)
{
if (fo->optype==OPDATE && so->optype==OPDATE)
{
fo->optype=OPINT;
fo->num=days(fo->date)-days(so->date);
return;
}
}
err("Wrong operand Type");
}